Dynomotion

Group: DynoMotion Message: 13766 From: Greg Carter Date: 10/3/2016
Subject: Windows .net API, Console handler
Hello,

I've been writing a small .net C# app to log/plot some data. To test it
I'm running this C program on a thread in Kflop, it just printf's some
hardcoded data in a loop:

#include "ExtendedLogging.h"
main()
{
Delay_sec(1.5);
int i = 0;
double T0 = Time_sec();
printf("Running Simple Thread...\n");
for(i=0;i<10;i++)
{
double tcurr = Time_sec() - T0;
// round times to neaarest servo tick
double tickcurr = ((int)(tcurr/TIMEBASE + 0.5))*TIMEBASE;
printf("%f,%d,%d,%d\n",tickcurr,40,60,80);
Delay_sec(1.5);
}
printf("Exiting Simple Thread.\n");
}

What I've found is that the Console Handler on the PC side only gets
called if I periodically grab a lock on the KM_Controller object, which
I'm doing in a thread like so:
async Task MsgTask()
{
LogTo.Info("Enter LoggingService.MsgTask");
//grab a Token to the KM_Controller so that the Console
Handler is called
while (!_cancelSource.IsCancellationRequested)
{
try
{
if (_kMotionService.KMController.WaitToken(100) ==
KMOTION_TOKEN.KMOTION_LOCKED)
{
//just grab it and release it, this seems to be
all that is needed to trigger
//the controller to call the Console Handler
_kMotionService.KMController.ReleaseToken();
}
await Task.Delay(100);
}
catch (OperationCanceledException)
{
break;
}
}
LogTo.Info("Exit LoggingService.MsgTask");
}

This is similar to what the SimpleFormsCS sample does but it uses a timer.

So my question is: is that how it is supposed to work? Seems odd that I
need to grab a lock to the KM_Controller to get the messages sent to the
console handler.

I'm using 4.34a, VS2015.
Thanks.
Greg.
Group: DynoMotion Message: 13767 From: Tom Kerekes Date: 10/4/2016
Subject: Re: Windows .net API, Console handler

Hi Greg,

The architecture for having multiple Applications, multiple Threads, multiple Boards all communicating in addition to asynchronous message paths through one USB Driver is fairly complex.   There is no mechanism for KFLOP to send an asynchronous message directly to an Application.   Unsolicited Console Messages need to be communicated:

#1 from KFLOP to the PC Host KMotionServer.exe

#2 from KMotion Server back to whatever Application is the Console Message handler for that KFLOP

In order for KFLOP to send a Console Message back to the Server some (any) application must perform a read operation from KFLOP.  At that point KMotionServer will have the Console Message in a queue.

As soon as the Client Application, that is the Console Message handler for that KFLOP, communicates with the KMotion Server for any reason (including requesting a Lock) the Console Message will be passed back to the Client.

Most Apps constantly read status from KFLOP so this is all handled automatically.  If you don't intend to read status continuously there is a .NET function ServiceConsole() that you can call.

There are better mechanisms for uploading data from KFLOP such as using the gather buffer commands.

HTH

Regards

TK




On 10/3/2016 9:14 PM, Greg Carter greg@... [DynoMotion] wrote:
 

Hello,

I've been writing a small .net C# app to log/plot some data. To test it
I'm running this C program on a thread in Kflop, it just printf's some
hardcoded data in a loop:

#include "ExtendedLogging.h"
main()
{
Delay_sec(1.5);
int i = 0;
double T0 = Time_sec();
printf("Running Simple Thread...\n");
for(i=0;i<10;i++)
{
double tcurr = Time_sec() - T0;
// round times to neaarest servo tick
double tickcurr = ((int)(tcurr/TIMEBASE + 0.5))*TIMEBASE;
printf("%f,%d,%d,%d\n",tickcurr,40,60,80);
Delay_sec(1.5);
}
printf("Exiting Simple Thread.\n");
}

What I've found is that the Console Handler on the PC side only gets
called if I periodically grab a lock on the KM_Controller object, which
I'm doing in a thread like so:
async Task MsgTask()
{
LogTo.Info("Enter LoggingService.MsgTask");
//grab a Token to the KM_Controller so that the Console
Handler is called
while (!_cancelSource.IsCancellationRequested)
{
try
{
if (_kMotionService.KMController.WaitToken(100) ==
KMOTION_TOKEN.KMOTION_LOCKED)
{
//just grab it and release it, this seems to be
all that is needed to trigger
//the controller to call the Console Handler
_kMotionService.KMController.ReleaseToken();
}
await Task.Delay(100);
}
catch (OperationCanceledException)
{
break;
}
}
LogTo.Info("Exit LoggingService.MsgTask");
}

This is similar to what the SimpleFormsCS sample does but it uses a timer.

So my question is: is that how it is supposed to work? Seems odd that I
need to grab a lock to the KM_Controller to get the messages sent to the
console handler.

I'm using 4.34a, VS2015.
Thanks.
Greg.


Group: DynoMotion Message: 13768 From: Greg Carter Date: 10/4/2016
Subject: Re: Windows .net API, Console handler
Hi Tom,
Previously I used the TriggerGather() function on KFlop, then at the end
of the Kflop user program used fprintf to write it to the PC. While
this works, it's not ideal for what I'm trying to do since the writes
take a while and I have to wait until the operation is over to get the
data. Ideally it would work like a ring buffer with the kflop user
program filling it, while the PC side empties it. Using printf in the
kflop user program seemed the simplest way to do that, and it seems to
work OK. On the PC side I have a thread call ServiceConsole every
10ms. I'm only calling printf every 4 cycles (for (k=0; k<4; k++)
WaitNextTimeSlice();).

For now I have it working enough for my needs, which were to get plots
instantly for tuning my (slow) axis (the plots are updated every 100ms
on the PC side). See attached screen shots. If you think the tool
might be useful for others (extended logging) and have any suggestions
on improving the data gathering I'll give implementing it a try.

Thanks for your help.
Greg
  @@attachment@@
Group: DynoMotion Message: 13769 From: Tom Kerekes Date: 10/4/2016
Subject: Re: Windows .net API, Console handler [2 Attachments]

Hi Greg,

Wow nice work.  Do you mind sharing it?

I was thinking as you describe.  Create a large circular buffer in the gather buffer that KFLOP continuously inserts data into.  KFLOP could set its write index into a persist variable to inform the PC where it is writing in the buffer.  The PC could then periodically read the write index and determine a block of data yet to be uploaded.  It could then upload that block of data as single hexadecimal binary block using  the GetGatherHex command.

http://dynomotion.com/Help/Cmd.htm#GetGatherHex

This has the advantage of not needing to convert the "floats" to decimal ASCII numbers which involves lots of double precision math.  It is exact with no rounding.   And takes fewer characters.   Also bigger blocks of data involve less handshaking and less flushing of data in the USB Buffer piplelines.

The TestUSB_Click function in the SimpleFormsCS Example uses this method.  My Computer shows this result:
PC->KFLOP N=100000 Int32, Time=1.289 sec, 688KBytes/sec
KFLOP->PC N=100000 Int32, Time=2.243 sec, 396KBytes/sec

But anyway since your method is fast enough and is simpler why change it?

Regards
TK


On 10/4/2016 7:22 PM, Greg Carter greg@... [DynoMotion] wrote:
 

Hi Tom,
Previously I used the TriggerGather() function on KFlop, then at the end
of the Kflop user program used fprintf to write it to the PC. While
this works, it's not ideal for what I'm trying to do since the writes
take a while and I have to wait until the operation is over to get the
data. Ideally it would work like a ring buffer with the kflop user
program filling it, while the PC side empties it. Using printf in the
kflop user program seemed the simplest way to do that, and it seems to
work OK. On the PC side I have a thread call ServiceConsole every
10ms. I'm only calling printf every 4 cycles (for (k=0; k<4; k++)
WaitNextTimeSlice();).

For now I have it working enough for my needs, which were to get plots
instantly for tuning my (slow) axis (the plots are updated every 100ms
on the PC side). See attached screen shots. If you think the tool
might be useful for others (extended logging) and have any suggestions
on improving the data gathering I'll give implementing it a try.

Thanks for your help.
Greg


Group: DynoMotion Message: 13770 From: Greg Carter Date: 10/4/2016
Subject: Re: Windows .net API, Console handler
Hi Tom,

I may look into your method for writing the data, but I'll finish up the logging first.  Right now I've hard coded the axis.  Once I make that a bit more configurable I'll share the code.

BTW the SimpleFormsCS has a bug and that's why the displayed read speed is half the write speed.  The timer should be reset in between the write and read.
Just after this comment:
// send the data (simple ramp)  (8 hex words per line)
add:
T0 = DateTime.Now;

Greg.

On 10/4/2016 11:44 PM, Tom Kerekes tk@... [DynoMotion] wrote:
 

Hi Greg,

Wow nice work.  Do you mind sharing it?

I was thinking as you describe.  Create a large circular buffer in the gather buffer that KFLOP continuously inserts data into.  KFLOP could set its write index into a persist variable to inform the PC where it is writing in the buffer.  The PC could then periodically read the write index and determine a block of data yet to be uploaded.  It could then upload that block of data as single hexadecimal binary block using  the GetGatherHex command.

http://dynomotion.com/Help/Cmd.htm#GetGatherHex

This has the advantage of not needing to convert the "floats" to decimal ASCII numbers which involves lots of double precision math.  It is exact with no rounding.   And takes fewer characters.   Also bigger blocks of data involve less handshaking and less flushing of data in the USB Buffer piplelines.

The TestUSB_Click function in the SimpleFormsCS Example uses this method.  My Computer shows this result:
PC->KFLOP N=100000 Int32, Time=1.289 sec, 688KBytes/sec
KFLOP->PC N=100000 Int32, Time=2.243 sec, 396KBytes/sec

But anyway since your method is fast enough and is simpler why change it?

Regards
TK

Group: DynoMotion Message: 13771 From: Tom Kerekes Date: 10/4/2016
Subject: Re: Windows .net API, Console handler

Ha!  Thanks Greg.

Now I get:

KFLOP->PC N=100000 Int32, Time=0.954 sec, 930KBytes/sec

TK


On 10/4/2016 9:05 PM, Greg Carter greg@... [DynoMotion] wrote:
 

Hi Tom,

I may look into your method for writing the data, but I'll finish up the logging first.  Right now I've hard coded the axis.  Once I make that a bit more configurable I'll share the code.

BTW the SimpleFormsCS has a bug and that's why the displayed read speed is half the write speed.  The timer should be reset in between the write and read.
Just after this comment:
// send the data (simple ramp)  (8 hex words per line)
add:
T0 = DateTime.Now;

Greg.

On 10/4/2016 11:44 PM, Tom Kerekes tk@... [DynoMotion] wrote:
 

Hi Greg,

Wow nice work.  Do you mind sharing it?

I was thinking as you describe.  Create a large circular buffer in the gather buffer that KFLOP continuously inserts data into.  KFLOP could set its write index into a persist variable to inform the PC where it is writing in the buffer.  The PC could then periodically read the write index and determine a block of data yet to be uploaded.  It could then upload that block of data as single hexadecimal binary block using  the GetGatherHex command.

http://dynomotion.com/Help/Cmd.htm#GetGatherHex

This has the advantage of not needing to convert the "floats" to decimal ASCII numbers which involves lots of double precision math.  It is exact with no rounding.   And takes fewer characters.   Also bigger blocks of data involve less handshaking and less flushing of data in the USB Buffer piplelines.

The TestUSB_Click function in the SimpleFormsCS Example uses this method.  My Computer shows this result:
PC->KFLOP N=100000 Int32, Time=1.289 sec, 688KBytes/sec
KFLOP->PC N=100000 Int32, Time=2.243 sec, 396KBytes/sec

But anyway since your method is fast enough and is simpler why change it?

Regards
TK